package com.example.bankingsystemandroid;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import android.app.Fragment;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.csc.bankingsystem.core.dto.AccountInfoDTO;
import com.csc.bankingsystem.core.dto.TransferMoneyDTO;
import com.example.bankingsystemandroid.Holder.InfoHolder;
import com.example.bankingsystemandroid.utils.PropertiesConfig;
import com.example.bankingsystemandroid.utils.PropertyManager;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

public class TransferFragment extends Fragment {

	Button btnConfirm;
	Spinner spinner;
	EditText editTextDestination;
	EditText editTextAmount;
	EditText editTextMessage;
	TextView textViewBalance;
	StableArrayAdapter spinnerAdapter = null;
	List<String> listNumber = new ArrayList<String>();
	List<AccountInfoDTO> listDTO = new ArrayList<AccountInfoDTO>();
	private ProgressBar mProgress;
	private TableLayout tableView;

	public TransferFragment() {
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {

		View v = inflater.inflate(R.layout.fragment_transfer, container, false);
		tableView = (TableLayout) v.findViewById(R.id.table_transfer_fragment);

		mProgress = (ProgressBar) v
				.findViewById(R.id.progress_bar_transfer_fragment);
		mProgress.bringToFront();
		mProgress.setIndeterminate(true);
		mProgress.setVisibility(View.VISIBLE);
		tableView.setVisibility(View.INVISIBLE);
		btnConfirm = (Button) v.findViewById(R.id.btnConfirm);
		editTextDestination = (EditText) v
				.findViewById(R.id.destination_fragment_transfer);
		editTextAmount = (EditText) v
				.findViewById(R.id.amount_fragment_transfer);
		editTextMessage = (EditText) tableView
				.findViewById(R.id.message_transfer_fragment);
		textViewBalance = (TextView) v
				.findViewById(R.id.balance_transfer_fragment);
		spinner = (Spinner) v
				.findViewById(R.id.account_spinner_fragment_transfer);

		GetAccountInfoTask accountInfoTask = new GetAccountInfoTask();
		accountInfoTask.execute();

		// Create an ArrayAdapter using the string array and a default spinner
		// layout
		spinnerAdapter = new StableArrayAdapter(getActivity().getBaseContext(),
				R.drawable.my_spinner, listDTO, listNumber);
		// ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
		// getActivity().getBaseContext(), R.array.country_arrays,
		// R.drawable.my_spinner);
		// Specify the layout to use when the list of choices appears
		spinnerAdapter
				.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		// Apply the adapter to the spinner
		spinner.setAdapter(spinnerAdapter);
		textViewBalance.setText("");

		btnConfirm.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				confirmTransfer();

			}
		});

		spinner.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> parentView,
					View selectedItemView, int position, long id) {
				AccountInfoDTO dto = ((StableArrayAdapter) spinner.getAdapter())
						.getAccountInfoDTO(position);
				textViewBalance.setText(dto.getAmount().toString());

			}

			@Override
			public void onNothingSelected(AdapterView<?> parentView) {
			}
		});
		return v;
	}

	public void confirmTransfer() {
		final String source = (String) spinner.getSelectedItem();
		final String dest = editTextDestination.getText().toString().trim();
		final String amount = editTextAmount.getText().toString().trim();
		final String message = editTextMessage.getText().toString().trim();

		if (!dest.matches("\\d+")) {
			editTextDestination.setError("Invalid destination account number");
		} else if (!amount.matches("\\d+")) {
			editTextAmount.setError("Invalid amount");
		} else if (message.length() == 0) {
			editTextMessage.setError("Message is required");
		} else {
			// do change password
			ArrayList<NameValuePair> postParameters;
			postParameters = new ArrayList<NameValuePair>();
			postParameters.add(new BasicNameValuePair("sourceAccountNumber",
					source));
			postParameters.add(new BasicNameValuePair(
					"destinationAccountNumber", dest));
			postParameters.add(new BasicNameValuePair("amount", amount));
			postParameters.add(new BasicNameValuePair("message", message));
			TransferMoneyTask transferMoneyTask = new TransferMoneyTask(
					getActivity());
			transferMoneyTask.execute(postParameters);
		}
	}

	private class StableArrayAdapter extends ArrayAdapter<String> {

		HashMap<String, AccountInfoDTO> mIdMap = new HashMap<String, AccountInfoDTO>();

		public StableArrayAdapter(Context context, int textViewResourceId,
				List<AccountInfoDTO> listAccount, List<String> listNumber) {
			super(context, textViewResourceId, listNumber);
			for (int i = 0; i < listAccount.size(); ++i) {
				mIdMap.put(listNumber.get(i), listAccount.get(i));
			}
		}

		public void initData(List<AccountInfoDTO> listAccount,
				List<String> listNumber) {
			for (int i = 0; i < listAccount.size(); ++i) {
				mIdMap.put(listNumber.get(i), listAccount.get(i));
			}
		}

		@Override
		public long getItemId(int position) {
			// String item = getItem(position);
			// return mIdMap.get(item).getId();
			return position;
		}

		@Override
		public boolean hasStableIds() {
			return true;
		}

		public AccountInfoDTO getAccountInfoDTO(int position) {
			String item = getItem(position);
			return mIdMap.get(item);
		}

		public AccountInfoDTO getAccountInfoDTO(String item) {
			return mIdMap.get(item);
		}

	}

	public class TransferMoneyTask extends
			AsyncTask<ArrayList<NameValuePair>, Void, String> {
		private Context context;
		private String amountAfterTransfer;

		public TransferMoneyTask(Context context) {
			super();
			this.context = context.getApplicationContext();
		}

		@Override
		protected String doInBackground(ArrayList<NameValuePair>... params) {
			/*
			 * Create the POST request
			 */
			HttpClient httpClient = new DefaultHttpClient();
			String serverIP = PropertiesConfig
					.getProperty(PropertyManager.SERVER_IP);
			String serverPort = PropertiesConfig
					.getProperty(PropertyManager.SERVER_PORT);

			HttpPost httpPost = new HttpPost("http://" + serverIP + ":"
					+ serverPort + "/bankingsystem/api/transfer-money");
			try {
				httpPost.setEntity(new UrlEncodedFormEntity(params[0]));
			} catch (UnsupportedEncodingException e2) {
				e2.printStackTrace();
			}
			/*
			 * Execute the HTTP Request
			 */
			try {
				httpPost.addHeader("Cookie",
						"JSESSIONID=" + InfoHolder.getSessionId());

				HttpResponse response = httpClient.execute(httpPost);
				HttpEntity respEntity = response.getEntity();
				if (respEntity != null) {
					try {
						JSONObject jsonObject = new JSONObject(
								EntityUtils.toString(respEntity));

						TransferMoneyDTO transferMoneyDTO = new TransferMoneyDTO();
						Gson gson = new Gson();
						transferMoneyDTO = gson.fromJson(jsonObject.toString(),
								TransferMoneyDTO.class);
						InfoHolder.setAccountInfoList(transferMoneyDTO
								.getAccountInfoDTOs());
						return transferMoneyDTO.getCode();
					} catch (JSONException e) {
						e.printStackTrace();
					}
				}

			} catch (ClientProtocolException e) {
				// writing exception to log
				e.printStackTrace();
			} catch (IOException e) {
				// writing exception to log
				e.printStackTrace();
			}
			return null;
		}

		@Override
		protected void onPostExecute(String result) {

			if ("SUCCESS".equals(result)) {
				Toast.makeText(context, "Transfer successful",
						Toast.LENGTH_SHORT).show();

				listDTO = InfoHolder.getAccountInfoList();
				listNumber.clear();
				for (AccountInfoDTO dto : listDTO) {
					listNumber.add(dto.getNumber());
				}
				spinnerAdapter.initData(listDTO, listNumber);
				spinnerAdapter.notifyDataSetChanged();
				AccountInfoDTO currentAccount = spinnerAdapter
						.getAccountInfoDTO((String) spinner.getSelectedItem());
				textViewBalance.setText(currentAccount.getAmount().toString());
				editTextDestination.setText("");
				editTextAmount.setText("");
				editTextMessage.setText("");
			} else if ("TRANSFER_INVALID_SOURCE".equals(result)) {
				Toast.makeText(context, "Invalid source account number",
						Toast.LENGTH_SHORT).show();
			} else if ("TRANSFER_INVALID_DESTINATION".equals(result)) {
				Toast.makeText(context, "Invalid destination account number!",
						Toast.LENGTH_SHORT).show();
			}
			super.onPostExecute(result);
		}

		public String getAmountAfterTransfer() {
			return amountAfterTransfer;
		}

		public void setAmountAfterTransfer(String amountAfterTransfer) {
			this.amountAfterTransfer = amountAfterTransfer;
		}
	}

	private class GetAccountInfoTask extends AsyncTask<Void, Void, Void> {

		@Override
		protected void onPostExecute(Void result) {
			listDTO = InfoHolder.getAccountInfoList();
			for (AccountInfoDTO dto : listDTO) {
				listNumber.add(dto.getNumber());
			}
			spinnerAdapter.initData(listDTO, listNumber);
			spinnerAdapter.notifyDataSetChanged();
			if (mProgress.getVisibility() == View.VISIBLE) {
				mProgress.setVisibility(View.GONE);
			}
			if (tableView.getVisibility() == View.INVISIBLE) {
				tableView.setVisibility(View.VISIBLE);
			}
			super.onPostExecute(result);
		}

		@Override
		protected Void doInBackground(Void... params) {
			/*
			 * Create the POST request
			 */
			String serverIP = PropertiesConfig
					.getProperty(PropertyManager.SERVER_IP);
			String serverPort = PropertiesConfig
					.getProperty(PropertyManager.SERVER_PORT);

			HttpClient httpClient = new DefaultHttpClient();
			HttpPost httpPost = new HttpPost("http://" + serverIP + ":"
					+ serverPort + "/bankingsystem/api/get-account-info");
			// Request parameters and other properties.

			try {

			} catch (Exception e) {
				// TODO: handle exception
			}
			/*
			 * Execute the HTTP Request
			 */
			try {
				httpPost.addHeader("Cookie",
						"JSESSIONID=" + InfoHolder.getSessionId());
				HttpResponse response = httpClient.execute(httpPost);
				HttpEntity respEntity = response.getEntity();

				if (response != null) {
					BufferedReader reader = new BufferedReader(
							new InputStreamReader(response.getEntity()
									.getContent(), "UTF-8"));

					StringBuilder builder = new StringBuilder();
					for (String line = null; (line = reader.readLine()) != null;) {
						builder.append(line).append("\n");
					}
					JSONTokener tokener = new JSONTokener(builder.toString());
					JSONArray finalResult = new JSONArray(tokener);

					ArrayList<AccountInfoDTO> accountInfoList = new ArrayList<AccountInfoDTO>();
					Gson gson = new Gson();
					Type collectionType = new TypeToken<ArrayList<AccountInfoDTO>>() {
					}.getType();
					accountInfoList = gson.fromJson(finalResult.toString(),
							collectionType);
					InfoHolder.setAccountInfoList(accountInfoList);
				}
			} catch (ClientProtocolException e) {
				// writing exception to log
				e.printStackTrace();
			} catch (IOException e) {
				// writing exception to log
				e.printStackTrace();
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return null;
		}
	}
}
